package org.peno.goud;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import lejos.nxt.*;


public class LRTesting {
	
	static int BROWN = 508;
	static int WHITE = 459;
	static int BLACK = 684;
	static int EDGE = 0;
	int[] barcode = new int[7];
	static ArrayList<Integer> stateDurations;;

	public LRTesting() {
		//echte data
		Integer[] states = {EDGE,-3,BLACK,-20,EDGE,-2,WHITE,-20,EDGE,-3,BLACK,-19,EDGE,-3,WHITE,-9,EDGE,-2};
		stateDurations = new ArrayList<Integer>(Arrays.asList(states));
	}
	
	public static void main(String[] args)
	{	
		LRTesting test = new LRTesting();
		test.interpretBarcode();

	}
	
	private void interpretBarcode()
	{
		// ============== EDGE states verwijderen en totale duration van barcode bepalen ====================
		int duration = 0;
		for (int i = 0; i < stateDurations.size();) {
			int curState = stateDurations.get(i);
			if (curState > 0) {
				// negatieve durations !!!
				System.out.println("the current state duration is : " + stateDurations.get(i + 1));
				duration += stateDurations.get(i + 1);
				System.out.println("the updated total duration is : " + duration);
				i+=2;
				
			} else if (curState == EDGE) {
				int edgeDur = -stateDurations.get(i + 1);
				int lower = edgeDur / 2;
				int upper = edgeDur - lower;
				System.out.println("lower = " + lower);
				System.out.println("upper = " + upper);
				if (i - 1 >= 0) {
					int updatedDurPrev = stateDurations.get(i - 1) - lower;
					stateDurations.set(i - 1, updatedDurPrev);
				}
				if (i + 3 < stateDurations.size()) {
					int updatedDurNext = stateDurations.get(i + 3) - upper;
					stateDurations.set(i + 3, updatedDurNext);
				}
				if (i > 0) {
					//want was er nog niet bijgeteld, upper wordt later bijgeteld:
					//niet doen voor eerste edge
					duration -= lower;
				}
				// remove deze EDGE state
				stateDurations.remove(i);
				// remove duration van deze EDGE state (deze is nu opgeschoven)
				stateDurations.remove(i);
			}
			
		}
		duration = -duration;
		System.out.println("the total duration is : " + duration);
		float barDuration = duration / 7;
		System.out.println("the bar Duraration is : " + barDuration);
		
		String msg = "The array is : { ";
		for (Iterator iterator = stateDurations.iterator(); iterator.hasNext();) {
			Integer temp = (Integer) iterator.next();
			msg = msg + temp + " ,";
		}
		msg = msg + " }";
		System.out.println(msg);
		
		// ============== streepjesLengte toewijzen aan elke state WHITE/BLACK ==================-
		int[][] stateAttribs = new int[7][3];
		int arrIndex = 0;
		for (int i = 0; i < stateDurations.size(); i++) {
			int curState = stateDurations.get(i);
			if (curState > 0) {
				// echte lengte van deze state
				int stateDur = -stateDurations.get(i + 1);
				// verschil tussen toegewezen streepjeslengte en echte lengte
				int rem = duration;
				// toegewezen streepjeslengte
				int assignedLength = 0;
				// vergelijk echte lengte met alle veelvouden van 1 gemiddelde streepjeslengte
				for (int j = 1; j <= 7; j++) {
					// currentRem < 0 betekent stateDur > j * barDuration
					// currentRem > 0 betekent stateDur < j * barDuration
					int currentRem = ((int) (j * barDuration)) - stateDur;
					if (Math.abs(currentRem) < Math.abs(rem)) {
						// verschil met toegewezen streepjeslengte
						rem = currentRem;
						// toegewezen streepjeslengte
						assignedLength = j;
					}
				}
				stateAttribs[arrIndex][0] = curState;
				stateAttribs[arrIndex][1] = rem;
				stateAttribs[arrIndex][2] = assignedLength;
				arrIndex++;
			}
		}
		if (arrIndex <= 6) {
			//  maak state negatief om einde aan te geven
			stateAttribs[arrIndex][0] = -1;
		}
		
		msg = "The array is : { ";
		for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
			msg = msg + "state: " + stateAttribs[i][0] + " , rem : " + stateAttribs[i][1] + " , assigned length: " + stateAttribs[i][2] + " , ";
		}
		msg = msg + " }";
		System.out.println(msg);
		
		
		// ================ check of totale streepjeslengte gelijk aan 7 en corrigeer indien nodig ==================
		int assignedLengthsSum = 0;
		for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
			assignedLengthsSum += stateAttribs[i][2];
		}
		
		System.out.println("The total number of bars before correction is: " + assignedLengthsSum);
		
		if (assignedLengthsSum > 7) {
			while (assignedLengthsSum != 7) {
				// zoek die state(index) met rem > 0 en grootste rem (dus echte lengte korter dan toegewezen en het minst dicht bij toegewezen lengte)
				int largestRem = 0;
				int wantedStateIndex = 7;
				for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
					if (stateAttribs[i][1] > largestRem) {
						largestRem = stateAttribs[i][1];
						wantedStateIndex = i;
					}
				}
				// assert dat hij er een gevonden heeft
				assert wantedStateIndex != 7;
				// maak toegewezen streepjeslengte 1 korter
				stateAttribs[wantedStateIndex][2] -= 1;
				// pas rem aan
				stateAttribs[wantedStateIndex][1] = (int) -(barDuration - largestRem);
				assignedLengthsSum = 0;
				for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
					assignedLengthsSum += stateAttribs[i][2];
				}
			}
		} else if (assignedLengthsSum < 7) {
			while (assignedLengthsSum != 7) {
				// zoek die state(index) met rem < 0 en kleinste rem (dus echte lengte langer dan toegewezen en het minst dicht bij toegewezen lengte)
				int smallestRem = 0;
				int wantedStateIndex = 7;
				for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
					if (stateAttribs[i][1] < smallestRem) {
						smallestRem = stateAttribs[i][1];
						wantedStateIndex = i;
					}
				}
				// assert dat hij er een gevonden heeft
				assert wantedStateIndex != 7;
				// maak toegewezen streepjeslengte 1 langer
				stateAttribs[wantedStateIndex][2] += 1;
				// pas rem aan
				stateAttribs[wantedStateIndex][1] = (int) barDuration + smallestRem; // smallest rem negatief
				assignedLengthsSum = 0;
				for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
					assignedLengthsSum += stateAttribs[i][2];
				}
			}
		}
		
		int k = 0;
		for (int i = 0; i < 7 && stateAttribs[i][0] > 0; i++) {
			for (int j = 0; j < stateAttribs[i][2]; j++) {
				barcode[k] = (stateAttribs[i][0] == BLACK) ? 1 : 0;
				k++;
			}
		}
		
		System.out.println("The barcode is " + barcode[0] + barcode[1] + barcode[2] + barcode[3] + barcode[4] + barcode[5] + barcode[6]);
	}
}